﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="RedRuler.cs" company="www.aboutdnn.com">
//   www.aboutdnn.com
// </copyright>
// <summary>
//   Defines the RedRuler type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace m2land.RedRuler
{
    using System;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;

    public partial class RedRuler : Form
    {
        private const int GripSize = 16;

        private decimal gripZoneRange = 16;
        private decimal defaultGripZoneRange = 16;
        private decimal maxClientHeight = 16;
        private decimal defaultMaxClientHeight = 36;


        private InfoPanel infoPanel;

        

        public RedRuler()
        {
            this.infoPanel = new InfoPanel();
            this.infoPanel.RedRulerForm = this;
            

            this.InitializeComponent();
            this.FormBorderStyle = FormBorderStyle.None;
            this.DoubleBuffered = true;
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.Opacity = 0.4;
            this.BackColor = Color.Red;
            this.TopMost = true;

            this.KeyPreview = true;
            this.KeyDown += this.OnKeyDown;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            var rc = new Rectangle(this.ClientSize.Width - GripSize, this.ClientSize.Height - GripSize, GripSize, GripSize);
            ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
        }

        /// <summary>
        /// This gives us the ability to resize the borderless from any borders instead of just the lower right corner
        /// </summary>
        /// <param name="m">Message parameter</param>
        protected override void WndProc(ref Message m)
        {
            const int WmNcHitTest = 0x84;
            const int HtLeft = 10;
            const int HtRight = 11;
            const int HtTop = 12;
            const int HtTopLeft = 13;
            const int HtTopRight = 14;
            const int HtBottom = 15;
            const int HtBottomLeft = 16;
            const int HtBottomRight = 17;

            if (m.Msg == WmNcHitTest)
            {
                var x = (int)(m.LParam.ToInt64() & 0xFFFF);
                var y = (int)((m.LParam.ToInt64() & 0xFFFF0000) >> 16);
                var pt = this.PointToClient(new Point(x, y));
                var clientSize = this.ClientSize;
                
                // allow resize on the lower right corner
                if (pt.X >= clientSize.Width - this.gripZoneRange && pt.Y >= clientSize.Height - this.gripZoneRange && clientSize.Height >= this.maxClientHeight)
                {
                    m.Result = (IntPtr)(this.IsMirrored ? HtBottomLeft : HtBottomRight);
                    return;
                }

                // allow resize on the lower left corner
                if (pt.X <= this.gripZoneRange && pt.Y >= clientSize.Height - this.gripZoneRange && clientSize.Height >= this.maxClientHeight)
                {
                    m.Result = (IntPtr)(this.IsMirrored ? HtBottomRight : HtBottomLeft);
                    return;
                }

                // allow resize on the upper right corner
                if (pt.X <= this.gripZoneRange && pt.Y <= this.gripZoneRange && clientSize.Height >= this.maxClientHeight)
                {
                    m.Result = (IntPtr)(this.IsMirrored ? HtTopRight : HtTopLeft);
                    return;
                }

                // allow resize on the upper left corner
                if (pt.X >= clientSize.Width - this.gripZoneRange && pt.Y <= 16 && clientSize.Height >= this.maxClientHeight)
                {
                    m.Result = (IntPtr)(this.IsMirrored ? HtTopLeft : HtTopRight);
                    return;
                }


                // allow resize on the top border
                if (pt.Y <= this.gripZoneRange && clientSize.Height >= this.maxClientHeight)
                {
                    m.Result = (IntPtr)(HtTop);
                    return;
                }

                // allow resize on the bottom border
                if (pt.Y >= clientSize.Height - this.gripZoneRange && clientSize.Height >= this.maxClientHeight)
                {
                    m.Result = (IntPtr)(HtBottom);
                    return;
                }

                // allow resize on the left border
                
                if (pt.X <= this.gripZoneRange && clientSize.Height >= this.maxClientHeight)
                {
                    m.Result = (IntPtr)(HtLeft);
                    return;
                }

                // allow resize on the right border
                if (pt.X >= clientSize.Width - this.gripZoneRange && clientSize.Height >= this.maxClientHeight)
                {
                    m.Result = (IntPtr)(HtRight);
                    return;
                }
            }
            base.WndProc(ref m);
        }

        private void OnKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Up:
                    this.Top--;
                    break;
                case Keys.Down:
                    this.Top++;
                    break;
                case Keys.Left:
                    this.Left--;
                    break;
                case Keys.Right:
                    this.Left++;
                    break;
                default:
                    break;
            }
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            this.Cursor = Cursors.SizeAll;
            this.ShowInfoPanel();
        }

        private void ShowInfoPanel()
        {
            if (this.infoPanel == null || this.infoPanel.IsDisposed)
            {
                this.infoPanel = new InfoPanel();
            }

            this.infoPanel.Show();
            this.infoPanel.Left = this.Left + (this.ClientSize.Width - this.infoPanel.Width);
            this.infoPanel.Top = this.Top + this.ClientSize.Height;
        }

        public const int WM_NCLBUTTONDOWN = 0xA1;
        public const int HT_CAPTION = 0x2;

        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
        [DllImport("user32.dll")]
        public static extern bool ReleaseCapture();

        /// <summary>
        /// This gives us the ability to drag the borderless form to a new location
        /// </summary>
        /// <param name="sender">Event Sender</param>
        /// <param name="e">Event arguments</param>
        private void OnMouseDown(object sender, MouseEventArgs e)
        {
            // ctrl-leftclick anywhere on the control to drag the form to a new location 
            if (e.Button == MouseButtons.Left)
            {
                ReleaseCapture();
                SendMessage(this.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
            }
        }
        

        private void Form1_Resize(object sender, EventArgs e)
        {
            this.labelSizeInfo.Text = string.Format(
                "Height: {0}, Width: {1}", this.ClientSize.Height, this.ClientSize.Width);
            this.infoPanel.numericUpDownHeight.Text = this.ClientSize.Height.ToString();
            this.infoPanel.numericUpDownWidth.Text = this.ClientSize.Width.ToString();

            //Adjust the grip area 
            if (this.ClientSize.Height < this.defaultMaxClientHeight)
            {
                this.gripZoneRange = 1;
                this.maxClientHeight = 2;
            }
            else
            {
                this.gripZoneRange = this.defaultGripZoneRange;
                this.maxClientHeight = this.defaultMaxClientHeight;
            }
        }

        private void RedRuler_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            var temp = this.Width;
            this.Width = this.Height;
            this.Height = temp;
        }

        private void label1_Click(object sender, EventArgs e)
        {

        }

        private void infoPanelToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.ShowInfoPanel();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}
